package com.sxbbc.common.core.service.system.pay;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;

import javax.servlet.http.HttpServletRequest;

import com.sxbbc.common.core.entity.jz.CPayLog;
import com.sxbbc.common.core.entity.jz.InfoAli;
import com.sxbbc.common.core.entity.jz.InfoWx;
import com.sxbbc.common.core.enums.*;
import com.sxbbc.common.core.service.*;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.function.common.GetRest;
import com.function.common.RestResponse;
import com.sxbbc.common.basics.enums.ServiceEnums;
import com.sxbbc.common.basics.exceptions.ThrowJsonException;
import com.sxbbc.common.basics.files.RestUploadFileInfo;
import com.sxbbc.common.basics.files.UploadUtils;
import com.sxbbc.common.basics.utils.calculation.CalcuUtils;
import com.sxbbc.common.basics.utils.date.DateUtil;
import com.sxbbc.common.basics.utils.statics.StaticUtils;
import com.sxbbc.common.core.alipay.AliCallBackUrls;
import com.sxbbc.common.core.alipay.AlipayUtils;
import com.sxbbc.common.core.utils.RedisUtils;
import com.sxbbc.common.core.wx.WxCallBackUrls;
import com.sxbbc.common.core.wx.WxPayUtils;

import common.Logger;

/**
 * 支付和回调业务层
 *
 * @author arno
 */
@Service
public class PayService {

    private static Logger logger = Logger.getLogger(PayService.class);
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private IAccountChangeService iAccountChangeService;
    @Autowired
    private ICPayLogService icPayLogService;
    @Autowired
    private OrderBackService orderBackService;



    /**
     * 处理支付逻辑签名
     *
     * @param log
     * @return
     */
    public RestResponse handleSign(CPayLog log) {
        //获取支付方式
        PayTypeEnums enums = PayTypeEnums.getEnums(log.getPayType());
        String msg = "";

        switch (enums) {
            case PAY_ZFB:
                //支付宝支付
                InfoAli ali = RedisUtils.getInstance().getAliInfo();
                //支付宝异步回调地址
                String asynchroUrl = ali.getReturnUrl() + AliCallBackUrls.ASYNCHRO_URL;
                //支付宝同步地址
                String synchroUrl = ali.getReturnUrl() + AliCallBackUrls.SYNCHRO_URL;
                if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.APP.getId())) {
                    //如果是支付宝APP支付
                    //1.如果是支付app
                    Map<String, Object> map = AlipayUtils.getAliPayApp(log.getPayCode(), log.getPayMoney().toPlainString(), asynchroUrl);
                    logger.info("支付宝APP签名结果：" + map);
                    return GetRest.getSuccess("成功", map, log.getPayCode());
                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.WEB.getId())) {
                    //如果是支付宝WEB支付
                    String form = AlipayUtils.getPCPay(log.getPayCode(), log.getPayMoney().toPlainString(), asynchroUrl, synchroUrl);
                    logger.info("支付宝WEB签名结果：" + form);
                    return GetRest.getSuccess("成功", form, log.getPayCode());
                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.MOBEIL.getId())) {
                    String map = AlipayUtils.ali_mobile_pay(log.getPayCode(), log.getPayMoney().toPlainString(), asynchroUrl, synchroUrl);
                    logger.info("支付宝手机端网页签名结果：" + map);
                    return GetRest.getSuccess("成功", map, log.getPayCode());
                }
                return GetRest.getFail("支付渠道来源错误");
            case PAY_WX:
                //微信支付
                //微信支付金额是以分为单位 需要放大100倍
                InfoWx infoWx = null;
                try {
                    infoWx = RedisUtils.getInstance().getWxInfo();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //微信回调地址
                String noticeUrl = infoWx.getReturnUrl() + WxCallBackUrls.ASYNCHRO_URL;
                //微信成功连接支付 手机跳转地址页面
                String successUrl = infoWx.getReturnUrl() + WxCallBackUrls.ASYNCHRO_URL;
                BigDecimal payMoney = CalcuUtils.getInstance().mul(log.getPayMoney(), new BigDecimal(100), 0);
                WxPayUtils wxPayUtils = WxPayUtils.getInstance();
                if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.APP.getId())) {
                    //如果是微信APP支付
                    SortedMap<Object, Object> map = wxPayUtils.getPayParaWxApp(log.getPayCode(), String.valueOf(payMoney.intValue()), noticeUrl);
                    logger.info("微信APP签名结果：" + map);
                    return GetRest.getSuccess("成功", map, log.getPayCode());
                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.WEB.getId())) {
                    //如果是微信WEB支付  扫描二维码支付
                    //支付链接
                    String codeUrl = wxPayUtils.getPayParaQrWeb(log.getPayCode(), String.valueOf(payMoney.intValue()), noticeUrl);
                    if (!StringUtils.isEmpty(codeUrl)) {
                        //生成支付二维码图片
                        RestUploadFileInfo result = UploadUtils.getInstance().uploadQr(codeUrl);
                        String qrurl = "";
                        if (result.isStatus()) {
                            qrurl = result.getData();
                        } else {
                            throw new ThrowJsonException(result.getDesc());
                        }
                        Map<String, Object> map = new HashMap<String, Object>();
                        map.put("paycode", log.getPayCode());
                        map.put("qrurl", qrurl);
                        map.put("paytype", log.getPayType());
                        map.put("money", log.getPayMoney());
                        map.put("confirmtime", new Date());
                        logger.info("微信二维码扫描签名结果：" + map);
                        return GetRest.getSuccess("成功", map, log.getPayCode());
                    } else {
                        throw new ThrowJsonException("支付二维码生成失败");
                    }

                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.WX_PUBLIC.getId())) {
                    //如果是微信公众号支付
                    SortedMap<Object, Object> map = wxPayUtils.getPayParaPublicAccounts(log.getOpenId(), log.getPayCode(), String.valueOf(payMoney.intValue()), noticeUrl);
                    logger.info("微信公众号签名结果：" + map);
                    return GetRest.getSuccess("成功", map, log.getPayCode());
                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.WX_PROGRAM.getId())) {
                    //如果是微信小程序支付
                    SortedMap<Object, Object> map = wxPayUtils.getPayParaProgram(log.getOpenId(), log.getPayCode(), String.valueOf(payMoney.intValue()), noticeUrl);
                    logger.info("微信小程序签名结果：" + map);
                    return GetRest.getSuccess("成功", map, log.getPayCode());
                } else if (CalcuUtils.getInstance().isEquals(log.getPayChannel(), PayChannlEnums.MOBEIL.getId())) {
                    //微信手机端打开网页支付
                    //支付链接
                    String mweb_url = wxPayUtils.getPayParaQrMobile(request, log.getPayCode(), String.valueOf(payMoney.intValue()), noticeUrl);
                    //拼接回调地址 订单列表页面
                    mweb_url = mweb_url + "&redirect_url=" + URLEncoder.encode(successUrl);
                    return GetRest.getSuccess("成功", mweb_url, log.getPayCode());
                }
                return GetRest.getFail("支付渠道来源错误");
            case PAY_MONEY:
                //余额支付
                Integer handleType = null;
                String remark = null;
                if (CalcuUtils.getInstance().isEquals(log.getServiceType(), ServiceEnums.ORDER.getId())) {
                    handleType = HandleTypeEnums.BUY.getId();
                    remark = HandleTypeEnums.BUY.getName();
                } else if (CalcuUtils.getInstance().isEquals(log.getServiceType(), ServiceEnums.OFFLINE_ORDER.getId())) {
                    handleType = HandleTypeEnums.BUY.getId();
                    remark = HandleTypeEnums.BUY.getName();
                } else if (CalcuUtils.getInstance().isEquals(log.getServiceType(), ServiceEnums.OFFLINE_BUY.getId())) {
                    handleType = HandleTypeEnums.OFFLINE_BUY.getId();
                    remark = HandleTypeEnums.OFFLINE_BUY.getName();
                } else if (CalcuUtils.getInstance().isEquals(log.getServiceType(), ServiceEnums.FARM_ORDER.getId())) {
                    handleType = HandleTypeEnums.FARM_BUY.getId();
                    remark = HandleTypeEnums.FARM_BUY.getName();
                }else if (CalcuUtils.getInstance().isEquals(log.getServiceType(), ServiceEnums.FARM_LOGISTICS_ORDER.getId())) {
                    handleType = HandleTypeEnums.FARM_LOGISTICS_ORDER.getId();
                    remark = HandleTypeEnums.FARM_LOGISTICS_ORDER.getName();
                }
                //1.扣除余额
                if (log.getPayMoney() != null && BigDecimal.ZERO.compareTo(log.getPayMoney()) < 0) {
                    msg = iAccountChangeService.insertCMoneyDetail(log.getCid(), handleType, StaticUtils.PAY_OUT,
                            log.getPayCode(), log.getPayMoney(), remark, log.getCid());
                    if (!StringUtils.isEmpty(msg)) {
                        throw new ThrowJsonException(msg);
                    }
                }
                //支付回调
                handlePayCallBack(log.getPayCode(), null);
                return GetRest.getSuccess("支付成功", null, log.getPayCode());
            case PAY_POINT:
                //积分支付
                handleType = HandleTypeEnums.POINT_BUY.getId();
                // 1.扣除积分
                if (log.getPoint() != null && BigDecimal.ZERO.compareTo(log.getPoint()) < 0) {
                    msg = iAccountChangeService.insertCPointDetail(log.getCid(), handleType, StaticUtils.PAY_OUT,
                            log.getPayCode(), log.getPoint(), "消费", log.getCid());
                    if (!StringUtils.isEmpty(msg)) {
                        throw new ThrowJsonException(msg);
                    }
                }
                // 2.扣除余额——如果有运费啥的
                if (log.getPayMoney() != null && BigDecimal.ZERO.compareTo(log.getPayMoney()) < 0) {
                    msg = iAccountChangeService.insertCMoneyDetail(log.getCid(), handleType, StaticUtils.PAY_OUT,
                            log.getPayCode(), log.getPayMoney(), "消费", log.getCid());
                    if (!StringUtils.isEmpty(msg)) {
                        throw new ThrowJsonException(msg);
                    }
                }
                //积分支付回调
                handlePayCallBack(log.getPayCode(), null);
                return GetRest.getSuccess("支付成功", null, log.getPayCode());
            default:
                return GetRest.getFail("暂未开通此类支付类型");
        }
    }

    /**
     * 处理支付回调
     *
     * @param payCode   平台交易单号
     * @param transCode 第三方交易单号
     */
    public void handlePayCallBack(String payCode, String transCode) {

        CalcuUtils calUtil = CalcuUtils.getInstance();
        QueryWrapper<CPayLog> wrapper = new QueryWrapper<>();
        wrapper.eq("pay_code", payCode);
        CPayLog cPayLog = icPayLogService.getOne(wrapper);
        if (cPayLog == null || calUtil.isEquals(StaticUtils.STATUS_YES, cPayLog.getStatus())) {
            throw new ThrowJsonException("交易不存在或已处理");
        }
        //2.根据版本号更新
        cPayLog.setStatus(StaticUtils.STATUS_YES);
        cPayLog.setTransCode(transCode);
        cPayLog.setPayTime(DateUtil.getInstance().currentDate());
        boolean flag = icPayLogService.updateById(cPayLog);
        if (!flag) {
            throw new ThrowJsonException("已处理");
        }
        //根据统一下单支付业务类型 获取对应的 资金金明细类型
        ServiceEnums enums = ServiceEnums.getEnums(cPayLog.getServiceType());

        switch (enums) {
            case ORDER:
            case OFFLINE_ORDER:
                //处理商城订单、线下订单回调
                orderBackService.handleOrderCallBack(cPayLog);
                break;
            case FARM_LOGISTICS_ORDER:
                //处理物流提鸡订单回调
                orderBackService.handleFarmLogisticsOrderCallBack(cPayLog);
                break;
            case FARM_ORDER:
                //处理农场订单回调
                orderBackService.handleFarmOrderCallBack(cPayLog);
                break;
            case OFFLINE_BUY:
                //处理线下买单订单回调
                orderBackService.handleOfflineBuyOrderCallBack(cPayLog);
            default:
                break;
        }
    }
}
